package com.siao.loader
{
	import com.siao.events.BytesEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;
	
	[Event(name="open", type="com.siao.events.BytesEvent")]
	
	[Event(name="complete", type="com.siao.events.BytesEvent")]
	
	[Event(name="error", type="com.siao.events.BytesEvent")]
	
	[Event(name="progress", type="flash.events.ProgressEvent")]
	
	/**
	 * 字节加载器
	 * @author SiaoLeon
	 */
	public class BytesLoader extends EventDispatcher
	{
		// -------------------------------------------------------------------------------------------------------- 静态常量
		
		// -------------------------------------------------------------------------------------------------------- 静态变量
		
		// -------------------------------------------------------------------------------------------------------- 静态方法
		
		// -------------------------------------------------------------------------------------------------------- 静态函数
		
		// -------------------------------------------------------------------------------------------------------- 属性
		
		private var _url:String;
		
		/**
		 * 加载地址
		 * @return
		 */
		public function get url():String
		{
			return this._url;
		}
		
		private var _speed:Number;
		
		/**
		 * 加载速度，单位：KB/S
		 * @return
		 */
		public function get speed():Number
		{
			return this._speed;
		}
		
		private var _content:*;
		
		/**
		 * 加载内容
		 * @return
		 */
		public function get content():*
		{
			return this._content;
		}
		
		private var _params:Object;
		
		/**
		 * 附带参数
		 * @return
		 */
		public function get params():Object
		{
			return this._params;
		}
		
		private var _connected:Boolean;
		
		/**
		 * @copy flash.net.URLStream.connected
		 * @return
		 */
		public function get connected():Boolean
		{
			return this.stream.connected;
		}
		
		// -------------------------------------------------------------------------------------------------------- 变量
		
		private var timer:int;
		
		private var loaded:Number;
		
		protected var stream:BytesStream;
		
		// -------------------------------------------------------------------------------------------------------- 构造
		
		/**
		 * 构造函数
		 * @param url 加载地址
		 * @param params 附带参数
		 */
		public function BytesLoader(url:String=null, params:Object=null)
		{
			this.stream = new BytesStream();
			this._url = url;
			this._params = params;
		}
		
		// -------------------------------------------------------------------------------------------------------- 方法
		
		/**
		 * 加载资源
		 * @param url 加载地址
		 * @param params 附带参数
		 */
		public function load(url:String=null, params:Object=null):void
		{
			this._connected = true;
			
			this._url = (url == null) ? this.url : url;
			this._params = (params == null) ? this.params : params;
			
			this.registerStreamEventListener();
			this.stream.load(new URLRequest(this.url));
		}
		
		/**
		 * 加载二进制数据
		 * @param bytes 字节数据
		 */
		public function loadBytes(bytes:ByteArray):void
		{
			var resolver:BytesResolver = new BytesResolver();
			resolver.addEventListener(BytesEvent.COMPLETE, onResolverComplete);
			resolver.addEventListener(BytesEvent.ERROR, onResolverError);
			resolver.parser(bytes);
		}
		
		/**
		 * 关闭加载流
		 */
		public function close():void
		{
			this.stream.close();
			this.removeStreamEventListener();
		}
		
		/**
		 * 重置
		 */
		public function reset():void
		{
			this._url = null;
			this._speed = NaN;
			this._params = null;
			this._content = null;
		}
		
		// -------------------------------------------------------------------------------------------------------- 函数
		
		/**
		 * 保存数据内容
		 * @param content 内容对象
		 */
		protected function save(content:*):void
		{
			this._content = content;
			this.dispatchEvent(new BytesEvent(BytesEvent.COMPLETE));
		}
		
		/**
		 * 注册二进制加载流的事件侦听
		 */
		private function registerStreamEventListener():void
		{
			this.stream.addEventListener(BytesEvent.OPEN, onOpen);
			this.stream.addEventListener(BytesEvent.COMPLETE, onComplete);
			this.stream.addEventListener(BytesEvent.ERROR, onError);
			this.stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
		}
		
		/**
		 * 移除二进制加载流的事件侦听
		 */
		private function removeStreamEventListener():void
		{
			this.stream.removeEventListener(BytesEvent.OPEN, onOpen);
			this.stream.removeEventListener(BytesEvent.COMPLETE, onComplete);
			this.stream.removeEventListener(BytesEvent.ERROR, onError);
			this.stream.removeEventListener(ProgressEvent.PROGRESS, onProgress);
		}
		
		/**
		 * 二进制加载流打开时
		 * @param event
		 */
		private function onOpen(event:Event):void
		{
			this._speed = 0;
			this.loaded = 0;
			this.timer = getTimer();
			this.dispatchEvent(new BytesEvent(BytesEvent.OPEN));
		}
		
		/**
		 * 二进制加载流完成时
		 * @param event
		 */
		private function onComplete(event:Event):void
		{
			var bytes:ByteArray = this.stream.data;
			
			this.close();
			this.loadBytes(bytes);
		}
		
		/**
		 * 二进制加载流错误时
		 * @param event
		 */
		private function onError(event:Event):void
		{
			this.close();
			this.dispatchEvent(new BytesEvent(BytesEvent.ERROR));
		}
		
		/**
		 * 二进制加载流进度时
		 * @param event
		 */
		private function onProgress(event:ProgressEvent):void
		{
			if (getTimer() - this.timer > 0)
			{
				this._speed = (event.bytesLoaded - this.loaded) / (getTimer() - this.timer);
				this.loaded = event.bytesLoaded;
				this.timer = getTimer();
			}
			
			this.dispatchEvent(event);
		}
		
		/**
		 * 解析二进制数据完成时
		 * @param event
		 */
		private function onResolverComplete(event:BytesEvent):void
		{
			var resolver:BytesResolver = event.target as BytesResolver;
			resolver.removeEventListener(Event.COMPLETE, onResolverComplete);
			resolver.removeEventListener(IOErrorEvent.IO_ERROR, onResolverError);
			
			this.save(resolver.content);
		}
		
		/**
		 * 解析二进制数据错误时
		 * @param event
		 */
		private function onResolverError(event:BytesEvent):void
		{
			event.target.removeEventListener(Event.COMPLETE, onResolverComplete);
			event.target.removeEventListener(IOErrorEvent.IO_ERROR, onResolverError);
			
			this.dispatchEvent(new BytesEvent(BytesEvent.ERROR));
		}
	
	}
}
